package git.soulbgm.utils;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import static git.soulbgm.constant.Constants.*;

/**
 * 获取主机工具类
 *
 * @author SoulBGM
 * @date 2020/6/28 15:46
 */
public class HostUtil {

    /**
     * 获得所有网络接口
     *
     * @return {@link List}<{@link NetworkInterface}>
     */
    public static List<NetworkInterface> getAllNetworkInterface() {
        try {
            Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
            List<NetworkInterface> interfaceList = new ArrayList<>(5);
            while (netInterfaces.hasMoreElements()) {
                interfaceList.add(netInterfaces.nextElement());
            }
            return interfaceList;
        } catch (Exception e) {
            throw new RuntimeException("get network interface error.");
        }
    }

    /**
     * 通过IP获取网络接口
     *
     * @param ip IP地址
     * @return {@link NetworkInterface}
     */
    public static NetworkInterface getNetworkInterfaceByIp(String ip) throws UnknownHostException {
        if (!isIp(ip)) {
            throw new UnknownHostException("IP格式错误");
        }
        List<NetworkInterface> interfaces = getAllNetworkInterface();
        for (NetworkInterface ni : interfaces) {
            Enumeration<InetAddress> ips = ni.getInetAddresses();
            while (ips.hasMoreElements()) {
                InetAddress inetAddress = ips.nextElement();
                String hostAddress = inetAddress.getHostAddress();
                if (hostAddress.equals(ip)) {
                    return ni;
                }
            }
        }
        return null;
    }

    /**
     * 通过网卡名称获取网络接口
     *
     * @param networkName 网卡名称
     * @return {@link NetworkInterface}
     */
    public static NetworkInterface getNetworkInterfaceByName(String networkName) {
        List<NetworkInterface> interfaces = getAllNetworkInterface();
        for (NetworkInterface ni : interfaces) {
            String name = ni.getName();
            if (name.equals(networkName)) {
                return ni;
            }
        }
        return null;
    }

    /**
     * 获取网络接口
     *
     * @return {@link NetworkInterface}
     */
    public static NetworkInterface getNetworkInterface() {
        List<NetworkInterface> interfaces = getAllNetworkInterface();
        for (NetworkInterface ni : interfaces) {
            String displayName = ni.getDisplayName();
            String name = ni.getName();
            // 判断网络接口的名称不能为 lo获得docker 我们要找的应该是 eth0
            if (!name.contains("docker") && !name.contains("lo") && !displayName.contains("VMware")
                    && !displayName.contains("virbr") && !displayName.contains("tun") && !displayName.contains("vnc")) {
                Enumeration<InetAddress> ips = ni.getInetAddresses();
                while (ips.hasMoreElements()) {
                    InetAddress inetAddress = ips.nextElement();
                    // 不是回环地址 127.0.0.1
                    if (!inetAddress.isLoopbackAddress()) {
                        String ip = inetAddress.getHostAddress();
                        if (isIp(ip)) {
                            return ni;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * 通过IP或网卡名称获取网络接口
     *
     * @param ipOrName IP或网卡名称
     * @param way      获得网络接口方式
     * @return {@link NetworkInterface}
     * @throws UnknownHostException 未知主机异常
     */
    public static NetworkInterface getNetworkInterface(String ipOrName, int way) throws UnknownHostException {
        if (way == GET_NETWORK_WAY_IP) {
            return getNetworkInterfaceByIp(ipOrName);
        } else if (way == GET_NETWORK_WAY_NAME) {
            return getNetworkInterfaceByName(ipOrName);
        }
        return getNetworkInterface();
    }

    /**
     * 获取网络接口的名称
     *
     * @return {@link String}
     */
    public static String getNetworkName() {
        return getNetworkName(getNetworkInterface());
    }

    /**
     * 获取网络接口的名称
     *
     * @param networkInterface 网络接口
     * @return {@link String}
     */
    public static String getNetworkName(NetworkInterface networkInterface) {
        if (networkInterface != null) {
            return networkInterface.getName();
        } else {
            throw new RuntimeException("get network interface name error. networkName = null.");
        }
    }

    /**
     * 获得主机IP
     *
     * @return {@link String}
     */
    public static String getHostIp() {
        return getHostIp(getNetworkInterface());
    }

    /**
     * 获得主机IP
     *
     * @param networkInterface 网络接口
     * @return {@link String}
     */
    public static String getHostIp(NetworkInterface networkInterface) {
        if (networkInterface != null) {
            Enumeration<InetAddress> ips = networkInterface.getInetAddresses();
            while (ips.hasMoreElements()) {
                InetAddress inetAddress = ips.nextElement();
                // 不是回环地址 127.0.0.1
                if (!inetAddress.isLoopbackAddress()) {
                    String ip = inetAddress.getHostAddress();
                    if (isIp(ip)) {
                        return ip;
                    }
                }
            }
        }
        throw new RuntimeException("get network interface name error. host = null.");
    }

    /**
     * 获得主机名
     *
     * @return {@link String}
     */
    public static String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
        }
        return "未知";
    }

    /**
     * ip正则表达式
     */
    private final static String IP_REGEX = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."
            + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
            + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
            + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";

    /**
     * 判断是否是IP地址的字符串
     *
     * @param ipAddress IP地址
     * @return 是否是IP
     */
    public static boolean isIp(String ipAddress) {
        return ipAddress.matches(IP_REGEX);
    }

}
